#include "UtilityPCH.h"
#include "UT_CameraOrtho.h"
#include "UT_MathHelper.h"

using namespace Utility;

//-----------------------------------------------------------------
UT_CameraOrtho::UT_CameraOrtho(const UT_AnimatedTransform &cam2world, const float screenWindow[4], 
	float sopen, float sclose, float lensr, float focald, UT_Film* film)
	: UT_CameraProjective(cam2world, UT_MathHelper::MakeTransform_Orthographic(0.0f,1.0f),
	  screenWindow,sopen,sclose,lensr,focald,film)
{
	m_kCameraXDiff = m_kRasterToCamera(UT_Vec3Float(1.0f,0.0f,0.0f));
	m_kCameraYDiff = m_kRasterToCamera(UT_Vec3Float(0.0f,1.0f,0.0f));
}
//-----------------------------------------------------------------
float UT_CameraOrtho::GenerateRay(const UT_CameraSample &sample, UT_Ray *ray) const
{
	// Generate raster and camera samples
	UT_Point3Float Pras(sample.m_fImageX, sample.m_fImageY, 0);
	UT_Point3Float Pcamera;
	m_kRasterToCamera(Pras, &Pcamera);
	
	*ray = UT_Ray(Pcamera, UT_Vec3Float(0,0,1), 0.f, UT_MathDefine::_INFINITY);
	
	// Modify ray for depth of field
	if (m_fLensRadius > 0.)
	{
		// Sample point on lens
		float lensU, lensV;
		ConcentricSampleDisk(sample.m_fLensU, sample.m_fLensV, &lensU, &lensV);
		lensU *= m_fLensRadius;
		lensV *= m_fLensRadius;

		// Compute point on plane of focus
		float ft				= m_fFocalDistance / ray->d.z;
		UT_Point3Float Pfocus	= (*ray)(ft);

		// Update ray for effect of lens
		ray->o = UT_Point3Float(lensU, lensV, 0.f);
		ray->d = UT_MathHelper::Normalize(Pfocus - ray->o);
	}

	ray->time = UT_MathHelper::Lerp(sample.m_fTime, m_fShutterOpenTime, m_fShutterCloseTime);

	m_kCameraToWorld(*ray, ray);
	return 1.0f;
}
//-----------------------------------------------------------------
float UT_CameraOrtho::GenerateRayDifferential(const UT_CameraSample &sample,UT_RayDifferential *ray) const
{
	// Compute main orthographic viewing ray

	// Generate raster and camera samples
	UT_Point3Float Pras(sample.m_fImageX, sample.m_fImageY, 0);
	UT_Point3Float Pcamera;
	m_kRasterToCamera(Pras, &Pcamera);
	*ray = UT_RayDifferential(Pcamera, UT_Vec3Float(0,0,1), 0.0f, UT_MathDefine::_INFINITY);

	// Modify ray for depth of field
	if (m_fLensRadius > 0.)
	{
		// Sample point on lens
		float lensU, lensV;
		ConcentricSampleDisk(sample.m_fLensU, sample.m_fLensV, &lensU, &lensV);
		lensU *= m_fLensRadius;
		lensV *= m_fLensRadius;

		// Compute point on plane of focus
		float ft				= m_fFocalDistance / ray->d.z;
		UT_Point3Float Pfocus	= (*ray)(ft);

		// Update ray for effect of lens
		ray->o = UT_Point3Float(lensU, lensV, 0.f);
		ray->d = UT_MathHelper::Normalize(Pfocus - ray->o);
	}
	
	ray->time = UT_MathHelper::Lerp(sample.m_fTime, m_fShutterOpenTime, m_fShutterCloseTime);

	ray->rxOrigin = ray->o + m_kCameraXDiff;
	ray->ryOrigin = ray->o + m_kCameraXDiff;
	ray->rxDirection = ray->ryDirection = ray->d;
	ray->hasDifferentials = true;

	m_kCameraToWorld(*ray, ray);
	return 1.0f;
}
//-----------------------------------------------------------------
//-----------------------------------------------------------------